/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.gidoo.xmldb;

import java.io.IOException;
import java.io.Writer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class  restores a xml element and it's children from the database
 * @author thomas
 */
public class RestoreXML
{

  private Writer buffer;
  private long elementID;
  private PreparedStatement psGetElement;
  private PreparedStatement psGetCharacters;
  private PreparedStatement psGetAttributes;
  private PreparedStatement psGetChildren;

  private Connection con;
  
  /** get xml for a specific element */
  public RestoreXML(long elementID, Connection connection, Writer buffer)
  {
    this.con = connection;
    this.buffer = buffer;
    this.elementID = elementID;
    init();
  }

  /** get XML for a whole document */
  public RestoreXML(String docname, Connection connection, Writer buffer)
  {
    this.buffer = buffer;
    this.con = connection;
    
    if(this.con != null)
    {
      try
      {
        // get root element
        Statement stmt = this.con.createStatement();
        ResultSet rs = stmt.executeQuery(
          "select c.id from contents as c, documents d " +
          "where c.id not in (select idchild from children) and " +
          "d.id = c.docid and d.NAME='" + docname + "'");
        if(rs.next())
        {
          long rootID = rs.getLong(1);
          this.elementID = rootID;
        }
        init();

      }
      catch(SQLException ex)
      {
        Logger.getLogger(RestoreXML.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
  }

  private void init()
  {
    if(con != null)
    {
      try
      {
        psGetElement =
          con.prepareStatement("select name, ns from elements where id=?");

        psGetCharacters =
          con.prepareStatement("select value from characters where id=?");

        psGetAttributes =
          con.prepareStatement("select name, ns,  value from attributes where " +
          "elementid=?");

        psGetChildren = con.prepareStatement(
          "select idchild from children where idparent=? " +
          "order by orderval");

      }
      catch(SQLException ex)
      {
        Logger.getLogger(RestoreXML.class.getName()).log(Level.SEVERE, null, ex);
      }

    }
  }

  public void startParsing()
  {
    RecursiveJob topRecursiveJob = new RecursiveJob(elementID);
    try
    {
      buffer.flush();
    }
    catch(IOException ex)
    {
      Logger.getLogger(RestoreXML.class.getName()).log(Level.SEVERE, null, ex);
    }
  }

  private class RecursiveJob
  {

    public RecursiveJob(long elementID)
    {
      try
      {

        psGetAttributes.setLong(1, elementID);
        psGetCharacters.setLong(1, elementID);
        psGetChildren.setLong(1, elementID);
        psGetElement.setLong(1, elementID);

        ResultSet rsElement = psGetElement.executeQuery();
        if(rsElement.next())
        {
          // element start
          String name = rsElement.getString(1);
          String prefix = rsElement.getString(2);
          buffer.append("<");
          if(prefix != null && !"".equals(prefix))
          {
            buffer.append(prefix);
            buffer.append(":");
          }
          buffer.append(name);
          rsElement.close();

          // attributes
          ResultSet rsAtt = psGetAttributes.executeQuery();
          while(rsAtt.next())
          {
            String attName = rsAtt.getString(1);
            String attPrefix = rsAtt.getString(2);
            String attValue = rsAtt.getString(3);

            buffer.append(" ");

            if(prefix != null && !"".equals(attPrefix))
            {
              buffer.append(attPrefix);
              buffer.append(":");
            }
            buffer.append(attName);
            buffer.append("=");
            buffer.append("\"");
            buffer.append(attValue);
            buffer.append("\"");
          }

          buffer.append(">");

          // all children
          ResultSet rsChildren = psGetChildren.executeQuery();
          LinkedList<Long> childrenList = new LinkedList<Long>();
          while(rsChildren.next())
          {
            childrenList.add(rsChildren.getLong(1));
          }
          rsChildren.close();

          for(Long childrenID : childrenList)
          {
            // recursion rules!
            RecursiveJob rj = new RecursiveJob(childrenID);
          }

          // end of element
          buffer.append("</");
          if(prefix != null && !"".equals(prefix))
          {
            buffer.append(prefix);
            buffer.append(":");
          }
          buffer.append(name);
          buffer.append(">");
        }
        else
        {
          //ups, may be a character only element
          ResultSet rsChars = psGetCharacters.executeQuery();
          if(rsChars.next())
          {
            String chars = rsChars.getString(1);
            buffer.append(chars);
          }
          rsChars.close();
        }

        buffer.flush();

      }
      catch(IOException ex)
      {
        Logger.getLogger(RestoreXML.class.getName()).log(Level.SEVERE, null, ex);
      }
      catch(SQLException ex)
      {
        Logger.getLogger(RestoreXML.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
  }
}
